#include <iostream>

#include "physics.h"
#include "Box2D.h"

Physics::~Physics()
{
 	// TODO: Empty world
}

Physics::Physics(float world_bottom,float world_left,float world_top,float world_right)
{
    // TODO: World boundary test
    
    // Set time remainder to zero - remainder used in calculating how many updates to
    // run this 'frame'
    time_remainder = 0;    
    
    // Create simulation world object, with zero gravity and static walls enclosing
    // Define the size of the world. 
	b2AABB worldAABB;
	worldAABB.lowerBound.Set(world_bottom, world_left);
	worldAABB.upperBound.Set(world_top, world_right);

	// Define the gravity vector.
	b2Vec2 gravity(0.0f, 0.0f);

	// Do we want to let bodies sleep?
	bool doSleep = true;

	// Construct a world object, which will hold and simulate the rigid bodies.
	world = new b2World(worldAABB, gravity, doSleep);
    boundary_walls = new Wall_List();
    
	// Define the walls.
	float midheight = (world_top-world_bottom)/2.0f;
	float midwidth = (world_right-world_left)/2.0f;
	
	boundary_walls->add_wall((world_right+world_left), world_bottom+DEFAULT_BARRIER_THICKNESS, midwidth-(DEFAULT_BARRIER_THICKNESS+DEFAULT_BARRIER_THICKNESS), DEFAULT_BARRIER_THICKNESS, AMBIENT_TEMPERATUTE, DEFAULT_HEAT_CONDUCTIVITY);
	boundary_walls->add_wall((world_right+world_left), world_top-DEFAULT_BARRIER_THICKNESS, midwidth-(DEFAULT_BARRIER_THICKNESS+DEFAULT_BARRIER_THICKNESS), DEFAULT_BARRIER_THICKNESS, AMBIENT_TEMPERATUTE, DEFAULT_HEAT_CONDUCTIVITY);
	boundary_walls->add_wall(world_left+DEFAULT_BARRIER_THICKNESS, (world_top+world_bottom), DEFAULT_BARRIER_THICKNESS, midheight, AMBIENT_TEMPERATUTE, DEFAULT_HEAT_CONDUCTIVITY);
    boundary_walls->add_wall(world_right-DEFAULT_BARRIER_THICKNESS, (world_top+world_bottom), DEFAULT_BARRIER_THICKNESS, midheight, AMBIENT_TEMPERATUTE, DEFAULT_HEAT_CONDUCTIVITY);	
}

void Physics::update(unsigned long timedelta)
{
    // timedelta should be in nanoseconds.
    // TIME_STEP should be in Hz.
    unsigned long totaltime = timedelta+time_remainder;
    int updates = static_cast<int>(totaltime / (TIME_STEP*1000000000.0f));
    time_remainder = static_cast<unsigned long>(totaltime-updates*TIME_STEP*1000000000.0f);
    
    std::cout << "Delta, Remain, updates  " << timedelta << ", " << time_remainder << ", " << updates << std::endl;
    
    for (int i=0; i!=updates;++i)
    {
        world->Step(TIME_STEP, ITERATIONS);
    }
}

void Physics::add_ship(float x, float y)
{
    // Do nothing...
}

void Physics::add_walls_to_world(Wall_List *wall_list)
{
    b2Body* wall_body;
    // float x, float y, float horiz_radius, float vert_radius
    for (wall_list->start();wall_list->current!=NULL;wall_list->next())
    {
        b2BodyDef wall;
        b2PolygonDef wall_shape;
        // wall
    	wall.position.Set(wall_list->current->x, wall_list->current->y);
    	// Call the body factory which allocates memory for the walls
    	wall_body = world->CreateBody(&wall);
    	// Define the ground box shape.
    	// The extents are the half-widths of the box.
    	wall_shape.SetAsBox(wall_list->current->half_width, wall_list->current->half_height);
    	// Add the ground shape to the ground body.
    	wall_body->CreateShape(&wall_shape);
    	// Add extra physical attributes
    	wall_body->SetUserData(&wall_list->current->state);
	}
}
